package com.ns.sbs.oauth.menu.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ns.basic.server.entry.ServerMenuEntry;
import com.ns.basic.server.mapper.ServerMenuEntryMapper;
import com.ns.core.current.config.SysConst;
import com.ns.core.utils.sg.ResultError;
import com.ns.core.vo.bs.BasicTreeVO;
import com.ns.core.vo.router.RouterMetaVO;
import com.ns.core.vo.router.RouterVO;
import com.ns.sbs.oauth.menu.dto.MenuPageDto;
import com.ns.sbs.oauth.menu.entry.MenuEntry;
import com.ns.sbs.oauth.menu.mapper.MenuEntryMapper;
import com.ns.sbs.oauth.menu.vo.MenuEntryVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务菜单业务实现层
 *
 * @author liaowei
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MenuServiceImpl extends ServiceImpl<MenuEntryMapper, MenuEntry> implements IMenuService {

    private final MenuEntryMapper mapper;

    private final ServerMenuEntryMapper serverMenuEntryMapper;

    @Override
    public Page<MenuEntryVO> selectBy(MenuPageDto dto) {

        // 返回菜单
        List<MenuEntryVO> menuTree = new ArrayList<>();

        // 查询当前服务菜单
        List<Long> serverMenus = this.getServerMenus(dto.getSid());
        dto.setIds(serverMenus);

        // 菜单列表
        List<MenuEntryVO> menus = mapper.selectByDto(dto);
        if (!CollectionUtils.isEmpty(menus)) {
            // 根菜单
            getMte(menus, menuTree);
        }

        // 排序
        menuTree = menuTree.stream().sorted(Comparator.comparingLong(MenuEntryVO::getSort)).toList();

        // 分页
        List<MenuEntryVO> list = menuTree.stream().skip((dto.getCurrent() - 1) * dto.getSize()).limit(dto.getSize()).toList();
        Page<MenuEntryVO> dictPage = new Page<>(dto.getCurrent(), dto.getSize());
        dictPage.setRecords(list);
        dictPage.setTotal(menuTree.size());
        // 组装数据
        return dictPage;
    }

    /**
     * 查询服务菜单
     *
     * @param sid 服务id
     * @return Long
     */
    @Override
    public List<Long> getServerMenus(Long sid) {
        Set<Long> ids = new HashSet<>();
        List<ServerMenuEntry> serverMenus = serverMenuEntryMapper.selectBySid(sid);
        if (!CollectionUtils.isEmpty(serverMenus)) {
            serverMenus.forEach(sm -> {
                if (Objects.nonNull(sm.getOne())) {
                    ids.add(sm.getOne());
                }
                if (Objects.nonNull(sm.getTwo())) {
                    ids.add(sm.getTwo());
                }
                if (Objects.nonNull(sm.getThree())) {
                    ids.add(sm.getThree());
                }
                if (Objects.nonNull(sm.getFour())) {
                    ids.add(sm.getFour());
                }
            });
        }
        return new ArrayList<>(ids);
    }

    /**
     * 根菜单
     *
     * @param menus 菜单
     * @param mte   处理完成菜单
     */
    private static void getMte(List<MenuEntryVO> menus, List<MenuEntryVO> mte) {
        List<Long> rts = new ArrayList<>();
        // 菜单-子菜单
        Map<Long, List<Long>> mf = new HashMap<>();
        // 菜单
        Map<Long, MenuEntryVO> map = new HashMap<>();
        for (MenuEntryVO menu : menus) {
            map.put(menu.getId(), menu);
            // 子菜单
            if (Objects.nonNull(menu.getPid())) {
                List<Long> mc = mf.getOrDefault(menu.getPid(), new ArrayList<>());
                mc.add(menu.getId());
                mf.put(menu.getPid(), mc);
            } else {
                rts.add(menu.getId());
            }
        }
        if (!CollectionUtils.isEmpty(rts)) {
            for (Long rt : rts) {
                MenuEntryVO childMenu = getChildMenu(rt, map, mf);
                mte.add(childMenu);
            }
        }
    }

    /**
     * 获取子菜单
     *
     * @param rt  父级菜单
     * @param map 菜单
     * @param mf  菜单-子菜单
     */
    private static MenuEntryVO getChildMenu(Long rt, Map<Long, MenuEntryVO> map, Map<Long, List<Long>> mf) {
        // 根菜单
        MenuEntryVO rm = map.get(rt);
        // 子菜单
        List<Long> mfs = mf.get(rt);
        if (!CollectionUtils.isEmpty(mfs)) {
            List<MenuEntryVO> children = new ArrayList<>();
            for (Long ml : mfs) {
                MenuEntryVO child = map.get(ml);
                if (Objects.nonNull(child)) {
                    children.add(child);
                }
                getChildMenu(ml, map, mf);
            }
            rm.setChildren(children);
        }
        return rm;
    }

    /**
     * 权限菜单
     *
     * @param holdMenus 拥有的权限
     * @return RouterVO
     */
    @Override
    public List<RouterVO> getDynamicMenu(List<Long> holdMenus) {
        List<RouterVO> routers = new ArrayList<>();
        try {
            // 查询菜单
            List<MenuEntryVO> menus = mapper.selectByIds(holdMenus);
            if (CollectionUtils.isEmpty(menus)) {
                return routers;
            }
            Map<Long, RouterVO> map = new ConcurrentHashMap<>();
            // 组装数据
            for (MenuEntryVO menu : menus) {
                RouterVO routerVO = new RouterVO();
                BeanUtils.copyProperties(menu, routerVO);
                RouterMetaVO meta = new RouterMetaVO();
                meta.setTitle(menu.getName());
                meta.setIcon(menu.getIcon());
                meta.setAffix(menu.getAffix());
                meta.setIsAuth(menu.getIsAuth());
                routerVO.setMeta(meta);
                if (Objects.isNull(menu.getPid())) {
                    map.put(menu.getId(), routerVO);
                } else {
                    RouterVO crt = map.get(menu.getPid());
                    if (Objects.isNull(crt)) {
                        continue;
                    }
                    List<RouterVO> children = crt.getChildren();
                    if (CollectionUtils.isEmpty(children)) {
                        children = new ArrayList<>();
                    }
                    children.add(routerVO);
                    crt.setChildren(children);
                    map.put(menu.getPid(), crt);
                }
            }
            routers = map.values().stream().toList();
            if (!CollectionUtils.isEmpty(routers)) {
                routers = routers.stream().sorted(Comparator.comparingLong(RouterVO::getSort)).toList();
            }
        } catch (Exception e) {
            throw new ResultError("菜单查询失败！");
        }
        return routers;
    }

    @Override
    public List<String> getMenuCode(List<Long> menus) {
        return mapper.getMenuCode(menus);
    }

    /**
     * 查询菜单
     *
     * @return List
     */
    @Override
    @Cacheable(cacheNames = SysConst.BASIC_MENU_TREE, key = "1", unless = "#result==null")
    public List<BasicTreeVO> getBasicMenu() {
        // 返回
        List<BasicTreeVO> trees = new ArrayList<>();
        try {
            // 查询菜单
            List<BasicTreeVO> menus = mapper.selectBasicMenu();
            if (CollectionUtils.isEmpty(menus)) {
                return trees;
            }
            Map<Long, BasicTreeVO> map = new ConcurrentHashMap<>();
            // 组装数据
            for (BasicTreeVO menu : menus) {
                BasicTreeVO routerVO = new BasicTreeVO();
                BeanUtils.copyProperties(menu, routerVO);
                if (Objects.isNull(menu.getPid())) {
                    map.put(menu.getId(), routerVO);
                } else {
                    BasicTreeVO bto = map.get(menu.getPid());
                    if (Objects.isNull(bto)) {
                        continue;
                    }
                    List<BasicTreeVO> children = bto.getChildren();
                    if (CollectionUtils.isEmpty(children)) {
                        children = new ArrayList<>();
                    }
                    children.add(routerVO);
                    bto.setChildren(children);
                    map.put(menu.getPid(), bto);
                }
            }
            trees = map.values().stream().toList();
            if (!CollectionUtils.isEmpty(trees)) {
                trees = trees.stream().sorted(Comparator.comparingLong(BasicTreeVO::getSort)).toList();
            }
        } catch (Exception e) {
            throw new ResultError("服务菜单查询失败！" + e.getMessage());
        }
        return trees;
    }

    @Override
    public List<BasicTreeVO> getMenuByMid(List<Long> sms) {
        List<BasicTreeVO> trees = new ArrayList<>();
        // 查询菜单
        List<BasicTreeVO> menus = mapper.selectTreeByIds(sms);
        if (CollectionUtils.isEmpty(menus)) {
            return trees;
        }
        // 菜单
        Map<Long, BasicTreeVO> map = new ConcurrentHashMap<>();
        // 组装数据
        for (BasicTreeVO bm : menus) {
            if (Objects.isNull(bm.getPid())) {
                // 先保存根菜单
                map.put(bm.getId(), bm);
            } else {
                // 非根菜单
                BasicTreeVO bto = map.get(bm.getPid());
                if (Objects.nonNull(bto)) {
                    List<BasicTreeVO> children = bto.getChildren();
                    if (CollectionUtils.isEmpty(children)) {
                        children = new ArrayList<>();
                    }
                    children.add(bm);
                    bto.setChildren(children);
                    map.put(bm.getPid(), bto);
                }
            }
        }
        trees = map.values().stream().toList();
        if (!CollectionUtils.isEmpty(trees)) {
            trees = trees.stream().sorted(Comparator.comparingLong(BasicTreeVO::getSort)).toList();
        }
        return trees;
    }
}
